package server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 
 */

/**
 * @author arpitagarwal
 * Copyright 2012, held by Arpit Agarwal, of University of Illinois at Urbana-Champaign. 
 */
public class MultiThreadedServer implements Runnable {

	protected int serverPort = 8080;
	protected ServerSocket serverSocket = null;
	protected boolean isStopped = false;
	protected Thread runningThread = null;
	public static final int NUM_WORKERS = 10;
	public ExecutorService threadPool = Executors
			.newFixedThreadPool(NUM_WORKERS);
	private static final boolean PRINT_YES_NO = true;
	public ArrayList<WorkerRunnable> workerList = new ArrayList<WorkerRunnable>();

	public MultiThreadedServer(int port) {
		this.serverPort = port;
	}

	public static final void print(String str) {
		if (PRINT_YES_NO) {
			System.out.println("Server: " + str);
		}
	}

	@Override
	public void run() {
		print("Starting Server @ PORT-" + serverPort);
		synchronized (this) {
			this.runningThread = Thread.currentThread();
		}
		openServerSocket();
		while (!isStopped()) {
			Socket clientSocket = null;
			try {
				clientSocket = this.serverSocket.accept();
			} catch (IOException e) {
				if (isStopped()) {
					print("Server Stopped");
					return;
				}
				throw new RuntimeException("Error accepting client connection",
						e);
			}
			WorkerRunnable workerObject = new WorkerRunnable(clientSocket,
					"Thread Pooled Server");
			workerList.add(workerObject);
			this.threadPool.execute(workerObject);
		}
		this.threadPool.shutdown();
		print("Server Stopped.");
		System.exit(0);
	}

	private synchronized boolean isStopped() {
		return this.isStopped;
	}

	public synchronized void stop() {
		this.isStopped = true;
		try {
			this.serverSocket.close();
		} catch (IOException e) {
			throw new RuntimeException("Error closing server", e);
		}
	}

	private void openServerSocket() {
		try {
			this.serverSocket = new ServerSocket(this.serverPort);
		} catch (IOException e) {
			throw new RuntimeException("Cannot open port 8080", e);
		}
	}
}
